﻿using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Xml.Linq;
using Toodledo.Model;

namespace Toodledo.Services.Helpers
{
    internal static class ToodledoExtensions
    {
        #region MD5 Hash
        public static string ComputeMd5HashString(this string toEncode)
        {
            MD5 md5 = MD5.Create();
            byte[] md5ByetArray = md5.ComputeHash(Encoding.Default.GetBytes(toEncode));
            var sb = new StringBuilder();
            for (int i = 0; i < md5ByetArray.Length; i++)
            {
                sb.Append(md5ByetArray[i].ToString("x2"));
            }
            return sb.ToString();
        }

        #endregion

        #region Get XML Elements and Attributes
        public static string GetElementValue(this XElement parent, XName child)
        {
            XElement element = parent.Element(child);
            return element == null ? string.Empty : element.Value;
        }

        public static string GetAttributeValue(this XElement parent, XName child)
        {
            XAttribute attribute = parent.Attribute(child);
            return attribute == null ? string.Empty : attribute.Value;
        }
        #endregion

        #region string to Toodledo Data Type
        private static bool ToToodledoBoolean(this string value)
        {
            if (string.IsNullOrEmpty(value))
                return false;
            if (value == "0")
                return false;
            if (value == "1")
                return true;
            return Convert.ToBoolean(value);
        }

        private static DateTime? ToToodledoDate(this string value)
        {
            if (string.IsNullOrEmpty(value))
                return null;
            DateTime dateValue;
            DateTime.TryParseExact(value, "YYYY-MM-DD", CultureInfo.InvariantCulture, DateTimeStyles.AssumeLocal,
                                   out dateValue);
            return dateValue;
        }

        private static TimeSpan? ToToodledoTime(this string value)
        {
            if (string.IsNullOrEmpty(value))
                return null;
            DateTime dateValue;
            DateTime.TryParseExact(value, "HH:MM AM", CultureInfo.InvariantCulture, DateTimeStyles.AssumeLocal,
                                   out dateValue);
            return dateValue - dateValue.Date;
        }

        private static int ToToodledoInt(this string value)
        {
            if (string.IsNullOrEmpty(value))
                return 0;
            int number;
            Int32.TryParse(value, NumberStyles.Number, CultureInfo.InvariantCulture, out number);
            return number;
        }
        #endregion

        #region XDocument to Toodledo Model Class
        public static List<Folder> AsFolderList(this XDocument response)
        {
            var folders = new List<Folder>();
            if (response.Root != null)
                folders.AddRange(response.Root.Elements("folder")
                                     .Select(xmlFolder => new Folder
                                                              {
                                                                  Name = xmlFolder.Value,
                                                                  Id = xmlFolder.GetAttributeValue("id"),
                                                                  IsPrivate =
                                                                      xmlFolder.GetAttributeValue("private").ToToodledoBoolean(),
                                                                  IsArchived =
                                                                      xmlFolder.GetAttributeValue("archived").ToToodledoBoolean(),
                                                                  Order =
                                                                      xmlFolder.GetAttributeValue("order").ToToodledoInt()
                                                              }));
            return folders;
        }

        public static List<Context> AsContextList(this XDocument response)
        {
            var contexts = new List<Context>();
            if (response.Root != null)
                contexts.AddRange(response.Root.Elements("context")
                                      .Select(xmlContext => new Context
                                                                {
                                                                    Name = xmlContext.Value,
                                                                    Id = xmlContext.GetAttributeValue("id")
                                                                }));
            return contexts;
        }

        public static List<Goal> AsGoalList(this XDocument response)
        {
            var goals = new List<Goal>();
            if (response.Root != null)
                goals.AddRange(response.Root.Elements("goal")
                                   .Select(xmlContext => new Goal
                                                             {
                                                                 Name = xmlContext.Value,
                                                                 Id = xmlContext.GetAttributeValue("id"),
                                                                 ContributesTo =
                                                                     xmlContext.GetAttributeValue("contributes"),
                                                                 Level = xmlContext.GetAttributeValue("level"),
                                                                 IsArchived =
                                                                     xmlContext.GetAttributeValue("archived").ToToodledoBoolean()
                                                             }));
            return goals;
        }

        public static List<GoalNote> AsGoalNoteList(this XDocument response)
        {
            var goalNotes = new List<GoalNote>();
            if (response.Root != null)
                goalNotes.AddRange(response.Root.Elements("goal")
                                       .Select(xmlGoalNotes => new GoalNote
                                                                   {
                                                                       Text = xmlGoalNotes.Value,
                                                                       GoalId = xmlGoalNotes.GetAttributeValue("id"),
                                                                   }));
            return goalNotes;
        }

        public static List<Task> AsTaskList(this XDocument response)
        {
            var tasks = new List<Task>();
            if (response.Root != null)
                tasks.AddRange(response.Root.Elements("task")
                                   .Select(xmlTask => new Task
                                                          {
                                                              Id = xmlTask.GetElementValue("id"),
                                                              Title = xmlTask.GetElementValue("title"),
                                                              Tag = xmlTask.GetElementValue("tag"),
                                                              FolderId = xmlTask.GetElementValue("folder"),
                                                              ContextId = xmlTask.GetElementValue("context"),
                                                              DueDate =
                                                                  xmlTask.GetElementValue("duedate").ToToodledoDate(),
                                                              DueTime =
                                                                  xmlTask.GetElementValue("duetime").ToToodledoTime(),
                                                              StartDate =
                                                                  xmlTask.GetElementValue("startdate").
                                                                  ToToodledoDate(),
                                                              StartTime =
                                                                  xmlTask.GetElementValue("starttime").
                                                                  ToToodledoTime(),
                                                              LengthInMinutes =
                                                                  xmlTask.GetElementValue("length").ToToodledoInt(),
                                                              Reminder =
                                                                  xmlTask.GetElementValue("reminder").ToToodledoInt(),
                                                              Repeat =
                                                                  xmlTask.GetElementValue("repeat").ToToodledoInt() >
                                                                  100
                                                                      ? (Task.TaskRepeat)
                                                                        (xmlTask.GetElementValue("repeat").
                                                                             ToToodledoInt() - 100)
                                                                      : (Task.TaskRepeat)
                                                                        (xmlTask.GetElementValue("repeat").
                                                                            ToToodledoInt()),
                                                              RepeatFrom = (Task.TaskRepeatFrom)(xmlTask.GetElementValue("repeat").ToToodledoInt() > 100 ? 100 : 0),
                                                              RepeatAdvance = xmlTask.GetElementValue("rep_advance"),
                                                              Status =
                                                                  (Task.TaskStatus)
                                                                  xmlTask.GetElementValue("status").ToToodledoInt(),
                                                              Priority =
                                                                  (Task.TaskPriority)
                                                                  xmlTask.GetElementValue("priority").ToToodledoInt(),
                                                              Star =
                                                                  xmlTask.GetElementValue("star").ToToodledoBoolean(),
                                                              Note = xmlTask.GetElementValue("note")
                                                          }));
            return tasks;
        }
        #endregion
    }
}